home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrtools-1.10 / lib / format.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-28  |  15.2 KB  |  726 lines

  1. /* @(#)format.c    1.29 98/03/31 Copyright 1985 J. Schilling */
  2. /*
  3.  *    format
  4.  *    common code for printf fprintf & sprintf
  5.  *
  6.  *    allows recursive printf with "%r", used in:
  7.  *    error, comerr, comerrno, errmsg, errmsgno and the like
  8.  *
  9.  *    Copyright (c) 1985 J. Schilling
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; see the file COPYING.  If not, write to
  24.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. #include <mconfig.h>
  28. #include <vadefs.h>
  29. #include <strdefs.h>
  30. #include <stdxlib.h>
  31. #ifndef    HAVE_STDLIB_H
  32. extern    char    *gcvt __PR((double, int, char *));
  33. #endif
  34. #include <standard.h>
  35. #include <schily.h>
  36.  
  37. /*
  38.  * Some CPU's (e.g. PDP-11) cannot do logical shifts.
  39.  * They use rotate instead. Masking the low bits before,
  40.  * makes rotate work too.
  41.  */
  42. #define    allmask(t)    ((unsigned t)~((unsigned t)0))
  43. #define    lowmask(t, x)    ((unsigned t)~((unsigned t)((1 << (x))-1) ))
  44. #define    rshiftmask(t, s)((allmask(t) & lowmask(t, s)) >> (s))
  45.  
  46. #define    CHARMASK    makemask(char)
  47. #define    SHORTMASK    makemask(short)
  48. #define    INTMASK        makemask(int)
  49. #define    LONGMASK    makemask(long)
  50.  
  51. #ifdef    DIVLBYS
  52. extern    long    divlbys();
  53. extern    long    modlbys();
  54. #else
  55. #define    divlbys(val, base)    ((val)/(base))
  56. #define    modlbys(val, base)    ((val)%(base))
  57. #endif
  58.  
  59. /*
  60.  *    We use macros here to avoid the need to link to the international
  61.  *    character routines.
  62.  *    We don't need internationalization for our purpose.
  63.  */
  64. #define    is_dig(c)    (((c) >= '0') && ((c) <= '9'))
  65. #define    is_cap(c)    ((c) >= 'A' && (c) <= 'Z')
  66. #define    to_cap(c)    (is_cap(c) ? c : c - 'a' + 'A')
  67. #define    cap_ty(c)    (is_cap(c) ? 'L' : 'I')
  68.  
  69. typedef unsigned int    Uint;
  70. typedef unsigned short    Ushort;
  71. typedef unsigned long    Ulong;
  72. #ifdef    HAVE_LONGLONG
  73. typedef unsigned long long    Ullong;
  74. #endif
  75.  
  76. typedef struct f_args {
  77.     void    (*outf) __PR((char, long)); /* Func from format(fun, arg) */
  78.     long    farg;                /* Arg from format (fun, arg) */
  79.     int    minusflag;
  80.     int    flags;
  81.     int    fldwidth;
  82.     int    signific;
  83.     int    lzero;
  84.     char    *buf;
  85.     char    *bufp;
  86.     char    fillc;
  87.     char    *prefix;
  88.     int    prefixlen;
  89. } f_args;
  90.  
  91. #define    MINUSFLG    1    /* '-' flag */
  92. #define    PLUSFLG        2    /* '+' flag */
  93. #define    SPACEFLG    4    /* ' ' flag */
  94. #define    HASHFLG        8    /* '#' flag */
  95.  
  96. LOCAL    void    prnum  __PR((Ulong, unsigned, f_args *));
  97. LOCAL    void    prdnum __PR((Ulong, f_args *));
  98. LOCAL    void    pronum __PR((Ulong, f_args *));
  99. LOCAL    void    prxnum __PR((Ulong, f_args *));
  100. LOCAL    void    prXnum __PR((Ulong, f_args *));
  101. LOCAL    int    prbuf  __PR((const char *, f_args *));
  102. LOCAL    int    prc    __PR((char, f_args *));
  103. LOCAL    int    prstring __PR((const char *, f_args *));
  104.  
  105.  
  106. #ifdef    PROTOTYPES
  107. EXPORT int format(    void (*fun)(char, long),
  108.             long farg,
  109.             const char *fmt,
  110.             va_list args)
  111. #else
  112. EXPORT int format(fun, farg, fmt, args)
  113.     register void    (*fun)();
  114.     register long    farg;
  115.     register char    *fmt;
  116.     va_list        args;
  117. #endif
  118. {
  119.     char buf[512];
  120.     const char *sfmt;
  121.     register int unsflag;
  122.     register long val;
  123.     register char type;
  124.     register char mode;
  125.     register char c;
  126.     int count;
  127.     int i;
  128.     short sh;
  129.     const char *str;
  130.     double dval;
  131.     Ulong res;
  132.     char *rfmt;
  133.     f_args    fa;
  134.  
  135.     fa.outf = fun;
  136.     fa.farg = farg;
  137.     count = 0;
  138.     /*
  139.      * Main loop over the format string.
  140.      * Increment and check for end of string is made here.
  141.      */
  142.     for(; *fmt != '\0'; fmt++) {
  143.         c = *fmt;
  144.         while (c != '%') {
  145.             if (c == '\0')
  146.                 return (count);
  147.             (*fun)(c, farg);
  148.             c = *(++fmt);
  149.             count++;
  150.         }
  151.  
  152.         /*
  153.          * We reached a '%' sign.
  154.          */
  155.         buf[0] = '\0';
  156.         fa.buf = fa.bufp = buf;
  157.         fa.minusflag = 0;
  158.         fa.flags = 0;
  159.         fa.fldwidth = 0;
  160.         fa.signific = -1;
  161.         fa.lzero = 0;
  162.         fa.fillc = ' ';
  163.         fa.prefixlen = 0;
  164.         sfmt = fmt;
  165.         unsflag = FALSE;
  166.     newflag:
  167.         switch (*(++fmt)) {
  168.  
  169.         case '+':
  170.             fa.flags |= PLUSFLG;
  171.             goto newflag;
  172.  
  173.         case '-':
  174.             fa.minusflag++;
  175.             goto newflag;
  176.  
  177.         case ' ':
  178.             /*
  179.              * If the space and the + flag are present,
  180.              * the space flag will be ignored.
  181.              */
  182.             fa.flags |= SPACEFLG;
  183.             goto newflag;
  184.  
  185.         case '#':
  186.             fa.flags |= HASHFLG;
  187.             goto newflag;
  188.  
  189.         case '0':
  190.             /*
  191.              * '0' is a flag.
  192.              */
  193.             fa.fillc = '0';
  194.             goto newflag;
  195.         }
  196.         if (*fmt == '*') {
  197.             fmt++;
  198.             fa.fldwidth = va_arg(args, int);
  199.             /*
  200.              * A negative fieldwith is a minus flag with a
  201.              * positive fieldwidth.
  202.              */
  203.             if (fa.fldwidth < 0) {
  204.                 fa.fldwidth = -fa.fldwidth;
  205. /*                fa.minusflag ^= 1;*/
  206.                 fa.minusflag = 1;
  207.             }
  208.         } else while (c = *fmt, is_dig(c)) {
  209.             fa.fldwidth *= 10;
  210.             fa.fldwidth += c - '0';
  211.             fmt++;
  212.         }
  213.         if (*fmt == '.') {
  214.             fmt++;
  215.             fa.signific = 0;
  216.             if (*fmt == '*') {
  217.                 fmt++;
  218.                 fa.signific = va_arg(args, int);
  219.                 if (fa.signific < 0)
  220.                     fa.signific = 0;
  221.             } else while (c = *fmt, is_dig(c)) {
  222.                 fa.signific *= 10;
  223.                 fa.signific += c - '0';
  224.                 fmt++;
  225.             }
  226.         }
  227.         if (strchr("UCSIL", *fmt)) {
  228.             /*
  229.              * Enhancements to K&R and ANSI:
  230.              *
  231.              * got a type specifyer
  232.              */
  233.             if (*fmt == 'U') {
  234.                 fmt++;
  235.                 unsflag = TRUE;
  236.             }
  237.             if (!strchr("CSILZODX", *fmt)) {
  238.                 /*
  239.                  * Got only 'U'nsigned specifyer,
  240.                  * use default type and mode.
  241.                  */
  242.                 type = 'I';
  243.                 mode = 'D';
  244.                 fmt--;
  245.             } else if (!strchr("CSIL", *fmt)) {
  246.                 /*
  247.                  * no type, use default
  248.                  */
  249.                 type = 'I';
  250.                 mode = *fmt;
  251.             } else {
  252.                 /*
  253.                  * got CSIL
  254.                  */
  255.                 type = *fmt++;
  256.                 if (!strchr("ZODX", mode = *fmt)) {
  257.                     fmt--;
  258.                     mode = 'D';/* default mode */
  259.                 }
  260.             }
  261.         } else switch(*fmt) {
  262.  
  263.         case 'h':
  264.             type = 'S';        /* convert to type */
  265.             goto getmode;
  266.  
  267.         case 'l':
  268.             type = 'L';        /* convert to type */
  269.  
  270.         getmode:
  271.             if (!strchr("udioxX", *(++fmt))) {
  272.                 fmt--;
  273.                 mode = 'D';
  274.             } else {
  275.                 mode = *fmt;
  276.                 if (mode != 'x')
  277.                     mode = to_cap(mode);
  278.                 if (mode == 'U')
  279.                     unsflag = TRUE;
  280.                 else if (mode == 'I')    /*XXX */
  281.                     mode = 'D';
  282.             }
  283.             break;
  284.         case 'x':
  285.             mode = 'x';
  286.             goto havemode;
  287.         case 'u':
  288.             unsflag = TRUE;
  289.         case 'o': case 'O':
  290.         case 'd': case 'D':
  291.         case 'i': case 'I':
  292.         case 'p':
  293.         case 'X':
  294.         case 'z': case 'Z':
  295.             mode = to_cap(*fmt);
  296.         havemode:
  297.             type = cap_ty(*fmt);
  298.             if (mode == 'I')    /*XXX kann entfallen*/
  299.                 mode = 'D';    /*wenn besseres uflg*/
  300.             break;
  301.  
  302.         case '%':
  303.             count += prc('%', &fa);
  304.             continue;
  305.         case ' ':
  306.             count += prbuf("", &fa);
  307.             continue;
  308.         case 'c':
  309.             c = va_arg(args, int);
  310.             count += prc(c, &fa);
  311.             continue;
  312.         case 's':
  313.             str = va_arg(args, char *);
  314.             count += prstring(str, &fa);
  315.             continue;
  316.         case 'b':
  317.             str = va_arg(args, char *);
  318.             fa.signific = va_arg(args, int);
  319.             count += prstring(str, &fa);
  320.             continue;
  321.  
  322. #ifndef    NO_FLOATINGPOINT
  323.         case 'e':
  324.             if (fa.signific == -1)
  325.                 fa.signific = 6;
  326.             dval = va_arg(args, double);
  327.             ftoes(buf, dval, 0, fa.signific);
  328.             count += prbuf(buf, &fa);
  329.             continue;
  330.         case 'f':
  331.             if (fa.signific == -1)
  332.                 fa.signific = 6;
  333.             dval = va_arg(args, double);
  334.             ftofs(buf, dval, 0, fa.signific);
  335.             count += prbuf(buf, &fa);
  336.             continue;
  337.         case 'g':
  338.             if (fa.signific == -1)
  339.                 fa.signific = 6;
  340.             if (fa.signific == 0)
  341.                 fa.signific = 1;
  342.             dval = va_arg(args, double);
  343.             gcvt(dval, fa.signific, buf);
  344.             count += prbuf(buf, &fa);
  345.             continue;
  346. #else
  347. #    ifdef    USE_FLOATINGARGS
  348.         case 'e':
  349.         case 'f':
  350.         case 'g':
  351.             dval = va_arg(args, double);
  352.             continue;
  353. #    endif
  354. #endif
  355.  
  356.         case 'r':            /* recursive printf */
  357.         case 'R':            /* recursive printf */
  358.             rfmt  = va_arg(args, char *);
  359.             /*
  360.              * I don't know any portable way to get an arbitrary
  361.              * C object from a var arg list so I use a
  362.              * system-specific routine __va_arg_list() that knows
  363.              * if 'va_list' is an array. You will not be able to
  364.              * assign the value of __va_arg_list() but it works
  365.              * to be used as an argument of a function.
  366.              * It is a requirement for recursive printf to be able
  367.              * to use this function argument. If your system
  368.              * defines va_list to be an array you need to know this
  369.              * via autoconf or another mechanism.
  370.              * It would be nice to have something like
  371.              * __va_arg_list() in stdarg.h
  372.              */
  373.             count += format(fun, farg, rfmt, __va_arg_list(args));
  374.             continue;
  375.  
  376.         case 'n':
  377.             {
  378.                 int    *ip = va_arg(args, int *);
  379.  
  380.                 *ip = count;
  381.             }
  382.             continue;
  383.  
  384.         default:            /* Unknown '%' format */
  385.             sfmt++;            /* Dont't print '%'   */
  386.             count += fmt - sfmt;
  387.             while (sfmt < fmt)
  388.                 (*fun)(*(sfmt++), farg);
  389.             if (*fmt == '\0') {
  390.                 fmt--;
  391.                 continue;
  392.             } else {
  393.                 (*fun)(*fmt, farg);
  394.                 count++;
  395.                 continue;
  396.             }
  397.         }
  398.         /*
  399.          * print numbers:
  400.          * first prepare type 'C'har, 'S'hort, 'I'nt, or 'L'ong
  401.          */
  402.         switch(type) {
  403.  
  404.         case 'C':
  405.             c = va_arg(args, int);
  406.             val = c;        /* extend sign here */
  407.             if (unsflag || mode != 'D')
  408. #ifdef    DO_MASK
  409.                 val &= CHARMASK;
  410. #else
  411.                 val = (unsigned char)val;
  412. #endif
  413.             break;
  414.         case 'S':
  415.             sh = va_arg(args, int);
  416.             val = sh;        /* extend sign here */
  417.             if (unsflag || mode != 'D')
  418. #ifdef    DO_MASK
  419.                 val &= SHORTMASK;
  420. #else
  421.                 val = (unsigned short)val;
  422. #endif
  423.             break;
  424.         case 'I':
  425.         default:
  426.             i = va_arg(args, int);
  427.             val = i;        /* extend sign here */
  428.             if (unsflag || mode != 'D')
  429. #ifdef    DO_MASK
  430.                 val &= INTMASK;
  431. #else
  432.                 val = (unsigned int)val;
  433. #endif
  434.             break;
  435.         case 'P':
  436.         case 'L':
  437.             val = va_arg(args, long);
  438.             break;
  439.         }
  440.  
  441.         /*
  442.          * Final print out, take care of mode:
  443.          * mode is one of: 'O'ctal, 'D'ecimal, or he'X'
  444.          * oder 'Z'weierdarstellung.
  445.          */
  446.         fa.bufp = &buf[sizeof(buf)-1];
  447.         *--fa.bufp = '\0';
  448.  
  449.         if (val == 0 && mode != 'D') {
  450.         printzero:
  451.             /*
  452.              * Printing '0' with fieldwidth 0 results in no chars.
  453.              */
  454.             fa.lzero = -1;
  455.             if (fa.signific >= 0)
  456.                 fa.fillc = ' ';
  457.             count += prstring("0", &fa);
  458.             continue;
  459.         } else switch(mode) {
  460.  
  461.         case 'D':
  462.             if (!unsflag && val < 0) {
  463.                 fa.prefix = "-";
  464.                 fa.prefixlen = 1;
  465.                 val = -val;
  466.             } else if (fa.flags & PLUSFLG) {
  467.                 fa.prefix = "+";
  468.                 fa.prefixlen = 1;
  469.             } else if (fa.flags & SPACEFLG) {
  470.                 fa.prefix = " ";
  471.                 fa.prefixlen = 1;
  472.             }
  473.             if (val == 0)
  474.                 goto printzero;
  475.         case 'U':
  476.             /* output a long unsigned decimal number */
  477.             prdnum(val, &fa);
  478.             break;
  479.         case 'O':
  480.             /* output a long octal number */
  481.             if (fa.flags & HASHFLG) {
  482.                 fa.prefix = "0";
  483.                 fa.prefixlen = 1;
  484.             }
  485.             pronum(val & 07, &fa);
  486.             if ((res = (val>>3) & rshiftmask(long, 3)) != 0)
  487.                 pronum(res, &fa);
  488.             break;
  489.         case 'p':
  490.         case 'x':
  491.             /* output a hex long */
  492.             if (fa.flags & HASHFLG) {
  493.                 fa.prefix = "0x";
  494.                 fa.prefixlen = 2;
  495.             }
  496.             prxnum(val & 0xF, &fa);
  497.             if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  498.                 prxnum(res, &fa);
  499.             break;
  500.         case 'P':
  501.         case 'X':
  502.             /* output a hex long */
  503.             if (fa.flags & HASHFLG) {
  504.                 fa.prefix = "0X";
  505.                 fa.prefixlen = 2;
  506.             }
  507.             prXnum(val & 0xF, &fa);
  508.             if ((res = (val>>4) & rshiftmask(long, 4)) != 0)
  509.                 prXnum(res, &fa);
  510.             break;
  511.         case 'Z':
  512.             /* output a binary long */
  513.             prnum(val & 0x1, 2, &fa);
  514.             if ((res = (val>>1) & rshiftmask(long, 1)) != 0)
  515.                 prnum(res, 2, &fa);
  516.         }
  517.         fa.lzero = -1;
  518.         /*
  519.          * If a precision (fielwidth) is specified
  520.          * on diouXx conversions, the '0' flag is ignored.
  521.          */
  522.         if (fa.signific >= 0)
  523.             fa.fillc = ' ';
  524.         count += prbuf(fa.bufp, &fa);
  525.     }
  526.     return (count);
  527. }
  528.  
  529. /*
  530.  * Routines to print (not negative) numbers in an arbitrary base
  531.  */
  532. LOCAL    unsigned char    dtab[]  = "0123456789abcdef";
  533. LOCAL    unsigned char    udtab[] = "0123456789ABCDEF";
  534.  
  535. LOCAL void prnum(val, base, fa)
  536.     register Ulong val;
  537.     register unsigned base;
  538.     f_args *fa;
  539. {
  540.     register char *p = fa->bufp;
  541.  
  542.     do {
  543.         *--p = dtab[modlbys(val, base)];
  544.         val = divlbys(val, base);
  545.     } while (val > 0);
  546.  
  547.     fa->bufp = p;
  548. }
  549.  
  550. LOCAL void prdnum(val, fa)
  551.     register Ulong val;
  552.     f_args *fa;
  553. {
  554.     register char *p = fa->bufp;
  555.  
  556.     do {
  557.         *--p = dtab[modlbys(val, (unsigned)10)];
  558.         val = divlbys(val, (unsigned)10);
  559.     } while (val > 0);
  560.  
  561.     fa->bufp = p;
  562. }
  563.  
  564. /*
  565.  * We may need to use division here too (PDP-11, non two's complement ...)
  566.  */
  567. LOCAL void pronum(val, fa)
  568.     register Ulong val;
  569.     f_args *fa;
  570. {
  571.     register char *p = fa->bufp;
  572.  
  573.     do {
  574.         *--p = dtab[val & 7];
  575.         val >>= 3;
  576.     } while (val > 0);
  577.  
  578.     fa->bufp = p;
  579. }
  580.  
  581. LOCAL void prxnum(val, fa)
  582.     register Ulong val;
  583.     f_args *fa;
  584. {
  585.     register char *p = fa->bufp;
  586.  
  587.     do {
  588.         *--p = dtab[val & 15];
  589.         val >>= 4;
  590.     } while (val > 0);
  591.  
  592.     fa->bufp = p;
  593. }
  594.  
  595. LOCAL void prXnum(val, fa)
  596.     register Ulong val;
  597.     f_args *fa;
  598. {
  599.     register char *p = fa->bufp;
  600.  
  601.     do {
  602.         *--p = udtab[val & 15];
  603.         val >>= 4;
  604.     } while (val > 0);
  605.  
  606.     fa->bufp = p;
  607. }
  608.  
  609. /*
  610.  * Final buffer print out routine.
  611.  */
  612. LOCAL int prbuf(s, fa)
  613.     register const char *s;
  614.     f_args *fa;
  615. {
  616.     register int diff;
  617.     register int rfillc;
  618.     register long arg            = fa->farg;
  619.     register void (*fun) __PR((char, long))    = fa->outf;
  620.     register int count;
  621.     register int lzero = 0;
  622.  
  623.     count = strlen(s);
  624.  
  625.     if (fa->lzero < 0 && count < fa->signific)
  626.         lzero = fa->signific - count;
  627.     diff = fa->fldwidth - lzero - count - fa->prefixlen;
  628.     count += lzero;
  629.     if (diff > 0)
  630.         count += diff;
  631.  
  632.     if (fa->prefixlen && fa->fillc != ' ') {
  633.         while (*fa->prefix != '\0')
  634.             (*fun)(*fa->prefix++, arg);
  635.     }
  636.     if (!fa->minusflag) {
  637.         rfillc = fa->fillc;
  638.         while (--diff >= 0)
  639.             (*fun)(rfillc, arg);
  640.     }
  641.     if (fa->prefixlen && fa->fillc == ' ') {
  642.         while (*fa->prefix != '\0')
  643.             (*fun)(*fa->prefix++, arg);
  644.     }
  645.     if (lzero > 0) {
  646.         rfillc = '0';
  647.         while (--lzero >= 0)
  648.             (*fun)(rfillc, arg);
  649.     }
  650.     while (*s != '\0')
  651.         (*fun)(*s++, arg);
  652.     if (fa->minusflag) {
  653.         rfillc = ' ';
  654.         while (--diff >= 0)
  655.             (*fun)(rfillc, arg);
  656.     }
  657.     return (count);
  658. }
  659.  
  660. /*
  661.  * Print out one char, allowing prc('\0')
  662.  * Similar to prbuf()
  663.  */
  664. #ifdef    PROTOTYPES
  665.  
  666. LOCAL int prc(char c, f_args *fa)
  667.  
  668. #else
  669. LOCAL int prc(c, fa)
  670.     char    c;
  671.     f_args *fa;
  672. #endif
  673. {
  674.     register int diff;
  675.     register int rfillc;
  676.     register long arg            = fa->farg;
  677.     register void (*fun) __PR((char, long))    = fa->outf;
  678.     register int count;
  679.  
  680.     count = 1;
  681.     diff = fa->fldwidth - 1;
  682.     if (diff > 0)
  683.         count += diff;
  684.  
  685.     if (!fa->minusflag) {
  686.         rfillc = fa->fillc;
  687.         while (--diff >= 0)
  688.             (*fun)(rfillc, arg);
  689.     }
  690.     (*fun)(c, arg);
  691.     if (fa->minusflag) {
  692.         rfillc = ' ';
  693.         while (--diff >= 0)
  694.             (*fun)(rfillc, arg);
  695.     }
  696.     return (count);
  697. }
  698.  
  699. /*
  700.  * String output routine.
  701.  * If fa->signific is >= 0, it uses only fa->signific chars.
  702.  * If fa->signific is 0, print no characters.
  703.  */
  704. LOCAL int prstring(s, fa)
  705.     register const char    *s;
  706.     f_args *fa;
  707. {
  708.     register char    *bp;
  709.     register int    signific;
  710.  
  711.     if (s == NULL)
  712.         return (prbuf("(NULL POINTER)", fa));
  713.  
  714.     if (fa->signific < 0)
  715.         return (prbuf(s, fa));
  716.  
  717.     bp = fa->buf;
  718.     signific = fa->signific;
  719.  
  720.     while (--signific >= 0 && *s != '\0')
  721.         *bp++ = *s++;
  722.     *bp = '\0';
  723.  
  724.     return (prbuf(fa->buf, fa));
  725. }
  726.